﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using CNav.Common;
using CNav.DataEntity;
using CNav.Domain;
using Microsoft.Practices.Unity;
using CNav.Business.Validation;

namespace CNav.Business.Services
{
    public interface IUserAccountService
    {
        ResponseData<UserProfile> Login(string email, string password, string machineIp);
        void LogOff(string email, string machineIp);
        ResponseData<UserProfile> GetUserByEmail(string email);
        ResponseData<UserProfile> GetUser(int id);
        ResponseData<UserProfileEx> GetUserProfileExById(int id);
        ResponseData<UserProfile> UpdateUser(UserProfile userprofile);

        void DeleteUser(int id);
    }

    public class UserAccountService : ServiceBase, IUserAccountService
    {
        public ResponseData<UserProfile> Login(string email, string password, string machineIp)
        {
            Argument.IsNotNull("username", email);
            Argument.IsNotNull("password", password);

            var response = new ResponseData<UserProfile>();

            var upperUsername = email.ToUpper();
            var encPassword = Services.Get<ISecurityService>().Encrypt(password);
            var profile = Context.Get<UserProfileDto>(u => u.Email == upperUsername && u.Password == encPassword).ToList().FirstOrDefault();

            if (profile != null)
            {
                var userProfile = new UserProfile();
                userProfile.ID = profile.ID;
                userProfile.BusinessID = profile.BusinessID;
                userProfile.IsBusinessAdmin = profile.IsBusinessAdmin ?? false;
                userProfile.UserPosition = profile.UserPosition;
                userProfile.PhoneNumber = profile.PhoneNumber;
                userProfile.FaxNumber = profile.FaxNumber;
                userProfile.Email = profile.Email;
                userProfile.Title = profile.Title;
                userProfile.FirstName = profile.FirstName;
                userProfile.LastName = profile.LastName;

                UpdateUserAccount(profile, machineIp, true);
                Context.Repository<UserProfileDto>().Update(profile);
                Context.Commit();

                response.Data = userProfile;
                return response;
            }

            //TODO: Log failed login attempt in DB
            response.Error = new[] { "Invalid username (email address) or password combination" };
            return response;
        }

        public void LogOff(string email, string machineIp)
        {
            var upperEmail = email.ToUpper();
            var profile = Context.Get<UserProfileDto>(u => u.Email == upperEmail).ToList().FirstOrDefault();

            if (profile != null)
            {
                UpdateUserAccount(profile, machineIp, false);
                profile.LogOffDate = DateTime.UtcNow;
                Context.Repository<UserProfileDto>().Update(profile);
                Context.Commit();
            }
        }

        public ResponseData<UserProfile> GetUserByEmail(string email)
        {
            Argument.IsNotNull("email", email);
            var uEmail = email.ToUpper();
            var profile = Context.Get<UserProfileDto>(u => u.Email == uEmail).ToList().FirstOrDefault();
            var response = new ResponseData<UserProfile>();

            if (profile != null)
            {
                var userProfile = new UserProfile();
                userProfile.ID = profile.ID;
                userProfile.BusinessID = profile.BusinessID;
                userProfile.IsBusinessAdmin = profile.IsBusinessAdmin ?? false;
                userProfile.UserPosition = profile.UserPosition;
                userProfile.PhoneNumber = profile.PhoneNumber;
                userProfile.FaxNumber = profile.FaxNumber;
                userProfile.Email = profile.Email;
                userProfile.Title = profile.Title;
                userProfile.FirstName = profile.FirstName;
                userProfile.LastName = profile.LastName;

                response.Data = userProfile;
                return response;
            }

            response.Error = new[] { "Invalid email address provided" };
            return response;
        }

        public ResponseData<UserProfile> GetUser(int id)
        {
            var response = new ResponseData<UserProfile>();

            var profile = Context.Get<UserProfileDto>(u => u.ID == id).ToList().FirstOrDefault();

            if (profile != null)
            {
                var userProfile = new UserProfile();
                userProfile.ID = profile.ID;
                userProfile.BusinessID = profile.BusinessID ;
                userProfile.IsBusinessAdmin = profile.IsBusinessAdmin ?? false;
                userProfile.UserPosition = profile.UserPosition;
                userProfile.PhoneNumber = profile.PhoneNumber;
                userProfile.FaxNumber = profile.FaxNumber;
                userProfile.Email = profile.Email;
                userProfile.Title = profile.Title;
                userProfile.FirstName = profile.FirstName;
                userProfile.LastName = profile.LastName;

                response.Data = userProfile;
                return response;
            }
            response.Error = new[] { "Invalid user id provided" };
            return response;
        }

        public ResponseData<UserProfileEx> GetUserProfileExById(int id)
        {
            var profile = Context.Get<UserProfileDto>(u => u.ID == id).ToList().FirstOrDefault();
            var response = new ResponseData<UserProfileEx>();

            if (profile != null)
            {
                var userProfile = new UserProfileEx();
                userProfile.ID = profile.ID;
                userProfile.BusinessID = profile.BusinessID;
                userProfile.IsBusinessAdmin = profile.IsBusinessAdmin ?? false;
                userProfile.UserPosition = profile.UserPosition;
                userProfile.PhoneNumber = profile.PhoneNumber;
                userProfile.FaxNumber = profile.FaxNumber;
                userProfile.Email = profile.Email;
                userProfile.Title = profile.Title;
                userProfile.FirstName = profile.FirstName;
                userProfile.LastName = profile.LastName;

                userProfile.IsLogOn = profile.IsLogOn;
                userProfile.LogOffDate = profile.LogOffDate;
                userProfile.LogOnAttempt = profile.LogOnAttempt;
                userProfile.LockOutExpireDate = profile.LockOutExpireDate;
                userProfile.PassExpireDate = profile.PassExpireDate;
                userProfile.AccountExpireDate = profile.AccountExpireDate;
                userProfile.MachineIP = profile.MachineIP;
                userProfile.Deleted = profile.Deleted;

                response.Data=userProfile;
                return response;
            }

            response.Error = new[] { "Invalid user id provided" };
            return response;
        }

        public ResponseData<UserProfile> UpdateUser(UserProfile userprofile)
        {
            var response = new ResponseData<UserProfile>();
            var validator = new UserProfileValidator();
            var validationResult = validator.Validate(userprofile);

            if (validationResult.IsValid)
            {
                var profileDto = Context.Get<UserProfileDto>(u => u.ID == userprofile.ID).ToList().FirstOrDefault();

                if (profileDto != null)
                {
                    profileDto.Title = userprofile.Title;
                    profileDto.UserPosition = userprofile.UserPosition;
                    profileDto.PhoneNumber = userprofile.PhoneNumber;
                    profileDto.FaxNumber = userprofile.FaxNumber;
                    profileDto.Title = userprofile.Title;
                    profileDto.FirstName = userprofile.FirstName;
                    profileDto.LastName = userprofile.LastName;

                    response.Data = userprofile;
                    return response;
                }
                response.Error = new[] { "Invalid user id provided" };
                return response;
            }
            response.Error = validationResult.ErrorList();
            return response;
        }

        private static void UpdateUserAccount(UserProfileDto profile, string machineIP, bool islogOn)
        {
            profile.IsLogOn = islogOn;
            profile.MachineIP = machineIP;
            profile.LogOnAttempt = 0;
            profile.LockOutExpireDate = null;
        }

        public void DeleteUser(int id)
        {
            var profile = Context.Get<UserProfileDto>(u => u.ID == id).ToList().FirstOrDefault();
            if (profile != null)
            {
                Context.Repository<UserProfileDto>().Delete(profile);
                Context.Commit();
            }
        }
    }
}